package com.yunshipei.common;

import android.os.Environment;
import android.text.TextUtils;

import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.net.EnterClient;
import com.yunshipei.core.utils.FileUtils;

import org.chromiun.net.ProxyChangeListener;
import org.json.JSONArray;
import org.json.JSONObject;
import org.reactivestreams.Publisher;
import org.spongycastle.util.encoders.Base64;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.functions.Function;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.http.Body;
import retrofit2.http.POST;
import retrofit2.http.Streaming;
import retrofit2.http.Url;

/**
 * 单独处理金格post下载，金格post下载，需要对byte字节进行截取，然后下载通过企业版wps打开，打开后编辑完成保存后上传
 */
public class KingGrid {

    private static final String DOWNLOAD_PATH = Environment.getExternalStorageDirectory().getPath() + "/yunshipei/download";
    private final OkHttpClient.Builder downloadClientBuilder = new OkHttpClient.Builder().connectTimeout(20 * 60, TimeUnit.SECONDS).readTimeout(20 * 60, TimeUnit.SECONDS).writeTimeout(20 * 60, TimeUnit.SECONDS);
    private final OkHttpClient.Builder uploadClientBuilder = new OkHttpClient.Builder().connectTimeout(20 * 60, TimeUnit.SECONDS).readTimeout(20 * 60, TimeUnit.SECONDS).writeTimeout(20 * 60, TimeUnit.SECONDS);


    private String data;
    private String downloadProxyIP = "";
    private int downloadProxyPort = 0;

    private String finalFileName = "";

    public KingGrid(String data, String downloadProxyIP, int downloadProxyPort) {
        this.data = data;
        this.downloadProxyIP = downloadProxyIP;
        this.downloadProxyPort = downloadProxyPort;
    }

    public Flowable<String> kingGridFileDownloadFlowable() {
        return Flowable.create(new FlowableOnSubscribe<Flowable<retrofit2.Response<ResponseBody>>>() {
            @Override
            public void subscribe(FlowableEmitter<Flowable<retrofit2.Response<ResponseBody>>> e) throws Exception {
                JSONObject dataObject = new JSONObject(data);
                //拼接请求参数
                String url = dataObject.optString("downloadUrl");
                finalFileName = dataObject.optString("docName", "") + dataObject.optString("docType", "");
                JSONArray jsonArray = dataObject.optJSONArray("downloadHttpParams");
                String requestParams = "";
                if (jsonArray != null) {
                    int len = jsonArray.length();
                    for (int i = 0; i < len; i++) {
                        JSONObject jsonObject = jsonArray.optJSONObject(i);
                        if (jsonObject != null) {
                            String key = jsonObject.optString("key");
                            String value = jsonObject.optString("value", "");
                            if (!TextUtils.isEmpty(key)) {
                                key = key.replaceAll("\\!\\@\\#\\$", " ");
                                requestParams += key + "=" + value + "\r\n";
                            }
                        }
                    }
                }
                RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), requestParams);
                //设置下载的cookie
                String cookie = "";
                JSONObject headerObjs = dataObject.optJSONObject("downloadHttpHeaders");
                if (headerObjs != null) {
                    cookie = headerObjs.optString("cookie", "");
                }
                if (!TextUtils.isEmpty(cookie)) {
                    final String finalCookie = cookie;
                    downloadClientBuilder.addInterceptor(new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            Request.Builder builder = chain.request().newBuilder();
                            builder.addHeader("Cookie", finalCookie);
                            return chain.proceed(builder.build());
                        }
                    });
                }
                //设置下载的代理
                OkHttpClient okHttpClient;
                if (!TextUtils.isEmpty(downloadProxyIP) && downloadProxyPort > 0) {
                    SocketAddress sa = new InetSocketAddress(downloadProxyIP, downloadProxyPort);
                    //定义代理，此处的Proxy是源自java.net
                    Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
                    okHttpClient = downloadClientBuilder.proxy(proxy).build();
                } else {
                    okHttpClient = downloadClientBuilder.build();
                }
                EnterClient.getInstances().initSSLClient(okHttpClient);
                ServiceApi serviceApi = new Retrofit.Builder().client(okHttpClient).baseUrl("http://127.0.0.1:8080").addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build().create(ServiceApi.class);
                Flowable<retrofit2.Response<ResponseBody>> downloadFlowable = serviceApi.post(url, requestBody);
                e.onNext(downloadFlowable);
            }
        }, BackpressureStrategy.BUFFER).flatMap(new Function<Flowable<retrofit2.Response<ResponseBody>>, Publisher<retrofit2.Response<ResponseBody>>>() {
            @Override
            public Publisher<retrofit2.Response<ResponseBody>> apply(Flowable<retrofit2.Response<ResponseBody>> responseFlowable) throws Exception {
                return responseFlowable;
            }
        }).flatMap(new Function<retrofit2.Response<ResponseBody>, Publisher<String>>() {
            @Override
            public Publisher<String> apply(retrofit2.Response<ResponseBody> response) throws Exception {
                int code = response.code();
                if (code == 200) {
                    String tempFileName = "temp_" + System.currentTimeMillis();
                    FileUtils.writeToFile(DOWNLOAD_PATH, tempFileName, response.body().byteStream());
                    String content = FileUtils.readFile(DOWNLOAD_PATH + File.separator + tempFileName);
                    String c64 = content.substring(0, 64);
                    Pattern p = Pattern.compile("\\s+(\\d*)\\s+(\\d*)\\s+(\\d*)\\s+");
                    Matcher matcher = p.matcher(c64);
                    int headerLength = 0;
                    int middleLength = 0;
                    int bodyLength = 0;
                    if (matcher.find()) {
                        headerLength = Integer.parseInt(matcher.group(1));
                        middleLength = Integer.parseInt(matcher.group(2));
                        bodyLength = Integer.parseInt(matcher.group(3));
                    } else {
                        return Flowable.error(new XCloudException("提取文件失败:" + code));
                    }
                    FileInputStream contentInputStream = new FileInputStream(DOWNLOAD_PATH + File.separator + tempFileName);
                    long skip = contentInputStream.skip(headerLength + middleLength + 64);
                    int byteCount = bodyLength;
                    OutputStream outputStream = new FileOutputStream(DOWNLOAD_PATH + File.separator + finalFileName);
                    byte[] bytes = new byte[byteCount];
                    int read = contentInputStream.read(bytes, 0, byteCount);
                    outputStream.write(bytes);
                    contentInputStream.close();
                    outputStream.close();
                    File tempFile = new File(DOWNLOAD_PATH + File.separator + tempFileName);
                    boolean b = tempFile.delete();
                    return Flowable.just(DOWNLOAD_PATH + File.separator + finalFileName);
                } else {
                    return Flowable.error(new XCloudException("下载失败,错误状态码:" + code));
                }
            }
        });
    }

    //金格文件上传，fileName为文件的全路径
    public Flowable<Boolean> kingGridUploadFlowable(final String fileName, final String uploadParam) {
        return Flowable.create(new FlowableOnSubscribe<Flowable<retrofit2.Response<ResponseBody>>>() {
            @Override
            public void subscribe(FlowableEmitter<Flowable<retrofit2.Response<ResponseBody>>> e) throws Exception {
                JSONObject jsonObject = new JSONObject(data);
                String url = jsonObject.optString("uploadUrl");
                //设置cookie
                String cookie = "";
                JSONObject headersObj = jsonObject.optJSONObject("uploadHttpHeaders");
                if (headersObj != null) {
                    cookie = headersObj.optString("cookie");
                }
                if (!TextUtils.isEmpty(cookie)) {
                    final String finalCookie = cookie;
                    uploadClientBuilder.addInterceptor(new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            Request.Builder builder = chain.request().newBuilder();
                            builder.addHeader("Cookie", finalCookie);
                            return chain.proceed(builder.build());
                        }
                    });
                }
                //拼接请求参数
                JSONArray uploadParams = jsonObject.optJSONArray("uploadHttpParams");
                String textParams = "";
                FileInputStream fileInputStream = new FileInputStream(fileName);
                long fileLength = fileInputStream.available();
                fileInputStream.close();
                if (uploadParams != null) {
                    int len = uploadParams.length();
                    for (int i = 0; i < len; i++) {
                        JSONObject paramObj = uploadParams.optJSONObject(i);
                        if (paramObj != null) {
                            String key = paramObj.optString("key");
                            String value = paramObj.optString("value", "");
                            if (!TextUtils.isEmpty(key)) {
                                key = key.replaceAll("\\!\\@\\#\\$", " ");
                                textParams += key + "=" + value + "\r\n";
                            }
                        }
                    }
                }
                if (!TextUtils.isEmpty(textParams)) {
                    if (textParams.contains("__file__length")) {
                        String fileLengthStr = fileLength + "";
                        String replaceAble = "__file__length";
                        for (int i = 0; i < fileLengthStr.length() - 1; i++) {
                            replaceAble += " ";
                        }
                        textParams = textParams.replace(replaceAble, fileLength + "");
                        if (textParams.contains("__file_length_base64_")) {
                            replaceAble = "__file_length_base64_";
                            textParams = textParams.replace(replaceAble, new String(Base64.encode((fileLength + "").getBytes())));
                        }
                    }
                    if (textParams.contains("__uploadNum__")) {
                        String replaceAble = "__uploadNum__";
                        int pos = textParams.indexOf("DBSTEP", 10);
                        if (pos < textParams.length() && pos != -1) {
                            textParams = textParams.replace(replaceAble, new String((textParams.length() - pos) + ""));
                        }
                    }
                    if (textParams.contains("__file__status")) {
                        textParams = textParams.replace("__file__status", uploadParam.split("=")[1]);
                    }
                }
                FileInputStream fis = new FileInputStream(fileName);
                int length = fis.available();
                byte[] fileBytes = new byte[length];
                int len = fis.read(fileBytes);
                fis.close();
                byte[] paramBytes = textParams.getBytes("UTF-8");
                byte[] totalBytes = byteMerger(paramBytes, fileBytes);
                RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), totalBytes);
                //设置代理
                String proxyIP = "";
                int proxyPort = 0;
                ProxyChangeListener.ProxyConfig proxyConfig = ProxyChangeListener.getProxyConfig();
                if (proxyConfig != null) {
                    proxyIP = proxyConfig.mHost;
                    proxyPort = proxyConfig.mPort;
                }
                OkHttpClient okHttpClient = null;
                if (!TextUtils.isEmpty(proxyIP) && proxyPort > 0) {
                    SocketAddress sa = new InetSocketAddress(proxyIP, proxyPort);
                    //定义代理，此处的Proxy是源自java.net
                    Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
                    okHttpClient = uploadClientBuilder.proxy(proxy).build();
                } else {
                    okHttpClient = uploadClientBuilder.build();
                }
                EnterClient.getInstances().initSSLClient(okHttpClient);
                ServiceApi serviceApi = new Retrofit.Builder().client(okHttpClient).baseUrl("http://127.0.0.1:8080").addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build().create(ServiceApi.class);
                Flowable<retrofit2.Response<ResponseBody>> uploadFlowable = serviceApi.post(url, requestBody);
                e.onNext(uploadFlowable);
            }
        }, BackpressureStrategy.BUFFER).flatMap(new Function<Flowable<retrofit2.Response<ResponseBody>>, Publisher<retrofit2.Response<ResponseBody>>>() {
            @Override
            public Publisher<retrofit2.Response<ResponseBody>> apply(Flowable<retrofit2.Response<ResponseBody>> responseFlowable) throws Exception {
                return responseFlowable;
            }
        }).flatMap(new Function<retrofit2.Response<ResponseBody>, Publisher<Boolean>>() {
            @Override
            public Publisher<Boolean> apply(retrofit2.Response<ResponseBody> response) throws Exception {
                int code = response.code();
                if (code == 200) {
                    return Flowable.just(true);
                } else {
                    return Flowable.error(new XCloudException("文件上传失败，状态码:" + code));
                }
            }
        });
    }

    private byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }

    private interface ServiceApi {
        @POST
        @Streaming
        Flowable<retrofit2.Response<ResponseBody>> post(@Url String url, @Body RequestBody requestBody);
    }
}
